import os
import jwt
from datetime import datetime
from functools import wraps
import requests
import oss2
from werkzeug.local import LocalProxy
from flask import request, jsonify, _request_ctx_stack
from setting import Config

current_identity = LocalProxy(lambda: getattr(_request_ctx_stack.top, 'current_identity', None))


def jwt_payload(identity):
    iat = datetime.utcnow()
    exp = iat + Config.JWT_EXPIRATION_DELTA
    return {'exp': exp, 'iat': iat, 'identity': identity}


def jwt_encode(identity):
    secret = Config.JWT_SECRET_KEY
    algorithm = Config.JWT_ALGORITHM
    required_claims = Config.JWT_REQUIRED_CLAIMS

    payload = jwt_payload(identity)
    missing_claims = list(set(required_claims) - set(payload.keys()))

    if missing_claims:
        raise RuntimeError('Payload is missing required claims: %s' % ', '.join(missing_claims))

    return jwt.encode(payload, secret, algorithm=algorithm, headers=None)


def jwt_decode(token):
    secret = Config.JWT_SECRET_KEY
    algorithm = Config.JWT_ALGORITHM
    leeway = Config.JWT_LEEWAY

    verify_claims = Config.JWT_VERIFY_CLAIMS
    required_claims = Config.JWT_REQUIRED_CLAIMS

    options = {
        'verify_' + claim: True
        for claim in verify_claims
    }
    options.update({
        'require_' + claim: True
        for claim in required_claims
    })

    return jwt.decode(token, secret, options=options, algorithms=[algorithm], leeway=leeway)


def jwt_required(fn):
    @wraps(fn)
    def wapper(*args, **kwargs):
        auth_header_value = request.headers.get('Authorization', None)
        if not auth_header_value:
            return jsonify(code='2100', msg='Authorization缺失')

        parts = auth_header_value.split()
        if len(parts) == 1:
            return jsonify(code='2100', msg='Token缺失')  # code 仅作为示例

        elif len(parts) > 2:
            return jsonify(code='2100', msg='Token无效')

        token = parts[1]
        if token is None:
            return jsonify(code='2100', msg='Token异常')

        try:
            payload = jwt_decode(token)
        except jwt.InvalidTokenError as e:
            return jsonify(code='2100', msg=str(e))

        _request_ctx_stack.top.current_identity = payload.get('identity')

        if payload.get('identity') is None:
            return jsonify(code='2100', msg='用户不存在')

        return fn(*args, **kwargs)

    return wapper


class UPLOAD_FILE(object):
    def __init__(self, subfilename, key="", password=""):

        auth = oss2.Auth(key, password)
        self.domain = 'https://pt-bucket-test1.oss-cn-hangzhou.aliyuncs.com'
        self.bucket = oss2.Bucket(auth, "https://oss-cn-hangzhou.aliyuncs.com", "pt-bucket-test1")
        # self.subfilename = subfilename  # oss 路径
        self.subfilename = 'iot-fota/xiumu'
        print(self.subfilename)

    def upload_file(self, path_list=None, path=None, type='content', content_file=None, content_name=None):
        osspath:str
        if path_list:
            list_file = os.listdir(path_list)
            for file in list_file:
                local_file = path_list + "\\" + "{}".format(file)
                osspath = self.subfilename + '/' + file
                print(osspath)
                self.up_file(osspath, local_file)
        elif path:
            osspath = self.subfilename + '/' + os.path.basename(path)
            local_file = path
            print(self.subfilename, ' -- ', local_file, '--', osspath)
            self.up_file(osspath, local_file)
        elif type == 'content':
            osspath = os.path.join(self.subfilename, content_name)
            exist = self.bucket.object_exists(osspath)
            if exist:
                print("oss have files with the same name, ignore oss upload")
            else:
                self.bucket.put_object(osspath, content_file)
                print(" {} 上传成功".format(osspath))
        else:
            print("未指定路径")
        return self.domain + '/' + osspath

    def up_file(self, osspath, local_file):
        # 先检测oss上是否有该文件
        exist = self.bucket.object_exists(osspath)
        if exist:
            print("oss have files with the same name, ignore oss upload")
        else:
            # 上传文件
            # with open(local_file, "rb") as fileobj:
            result1 = self.bucket.put_object_from_file(osspath, local_file)
            print("{0} 上传成功".format(osspath))
            print(result1.status, result1.resp, result1.headers, result1.etag, result1.crc)
            if int(result1.status) != 200:
                print("oss upload faild %s" % osspath)

    def delete(self, filename):
        # 删除文件。
        # yourObjectName填写待删除文件的完整路径，完整路径中不包含Bucket名称，例如exampledir/exampleobject.txt。
        # 如需删除文件夹，请将yourObjectName设置为对应的文件夹名称。如果文件夹非空，则需要将文件夹下的所有文件删除后才能删除该文件夹。
        ret = self.bucket.delete_object(filename)
        print(ret.delete_marker)
        if ret:
            return True


def oss2_data(oss_class, datasurl, name):
    if datasurl:
        try:
            print(datasurl)
            res = requests.get(datasurl, timeout=5, verify=False)
            content_name = name
            content_file = res.content
            osspath = oss_class.upload_file(type='content', content_name=content_name, content_file=content_file)
            return osspath
        except Exception as e:
            print(e)
            return None
